package com.ellfors.module_first.dialog_queue

import android.app.Activity
import android.app.Dialog
import android.content.ContextWrapper
import android.content.DialogInterface
import androidx.appcompat.app.AppCompatActivity
import com.ellfors.common.ext.logD
import com.ellfors.common.ext.logI
import com.ellfors.common.ext.logW
import com.ellfors.module_first.R
import com.ellfors.module_first.dialog_queue.DialogQueueManager.dismissWithQueue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.lang.ref.WeakReference
import java.util.WeakHashMap

/**
 * Dialog队列管理器
 *
 * 依照优先级显示Dialog，优先级高的显示优先
 * 同步Dialog可以与其他Dialog同步展示，并且互不影响
 * 显示：[Dialog.showWithQueue]
 * 隐藏：[Dialog.dismissWithQueue]
 *
 * 可以兼容DialogFragment，对应的Fragment需要实现[DialogQueueInterface]接口，
 * 显示：[DialogQueueInterface.showWithQueue]
 * 隐藏：[DialogQueueInterface.dismissWithQueue]
 *
 * 公用：
 * 清空: [clearQueue]
 */
object DialogQueueManager {

    /**
     * 优先级 — 默认
     * 正常排队展示
     */
    const val PRIORITY_DEFAULT = 0

    /**
     * 优先级 — 中
     * 无论当前是否有Dialog弹出，都立即弹出它，后续排队
     */
    const val PRIORITY_MIDDLE = 1

    /**
     * 优先级 — 高
     * 立即弹出它，同时取消掉所以其他Dialog，并且在它存在期间，其他Dialog不允许入列
     */
    const val PRIORITY_HIGH = 2

    //待展示的Dialog队列
    private val _dialogQueue = mutableListOf<DialogWrapper>()

    //每个Dialog原有的OnDismiss监听
    private val _dismissListenerMap = WeakHashMap<Dialog, DialogInterface.OnDismissListener>()

    //当前展示的弹出集合
    private var _currentShowDialogs = mutableListOf<DialogWrapper>()

    //协程作用域
    private val _scope by lazy { CoroutineScope(SupervisorJob() + Dispatchers.Main) }

    /**
     * 根据队列优先级显示Dialog
     *
     * @param priority 优先级（默认为Default）
     * @param firstShowDelay 首次弹出的延迟时间，单位为毫秒（默认为0）
     * @param intervalWithLast 与队列中前一个Dialog的间隔时间，单位为毫秒（默认为0）
     */
    fun Dialog?.showWithQueue(
        priority: Int = PRIORITY_DEFAULT,
        firstShowDelay: Long = 0,
        intervalWithLast: Long = 0,
    ) {
        this ?: return
        val wrapper = DialogWrapper(
            dialog = this,
            priority = priority,
            firstShowDelay = firstShowDelay,
            intervalWithLast = intervalWithLast,
            insertTime = System.currentTimeMillis()
        )
        handleShowDialog(wrapper)
    }

    /**
     * 在队列中移除Dialog
     */
    fun Dialog?.dismissWithQueue() {
        this ?: return
        //当前展示的有它则直接dismiss
        _currentShowDialogs.find { it.dialog == this }?.dismiss()
        //从队列中移除
        _dialogQueue.find { it.dialog == this }?.also {
            _dialogQueue.remove(it)
        }
        //移除监听
        _dismissListenerMap.remove(this)
    }

    /**
     * 设置Dialog的OnDismissListener
     */
    fun Dialog?.setOnDismissListenerWithQueue(listener: DialogInterface.OnDismissListener) {
        this ?: return
        _dismissListenerMap[this] = listener
    }

    /**
     * 根据队列优先级显示DialogFragment
     *
     * @param activity 显示的Activity
     * @param priority 优先级（默认为Default）
     * @param firstShowDelay 首次弹出的延迟时间，单位为毫秒（默认为0）
     * @param intervalWithLast 与队列中前一个Dialog的间隔时间，单位为毫秒（默认为0）
     */
    fun DialogQueueInterface?.showWithQueue(
        activity: AppCompatActivity,
        priority: Int = PRIORITY_DEFAULT,
        firstShowDelay: Long = 0,
        intervalWithLast: Long = 0,
    ) {
        this ?: return
        val wrapper = DialogWrapper(
            dialogFragment = this,
            fragmentActivity = WeakReference(activity),
            priority = priority,
            firstShowDelay = firstShowDelay,
            intervalWithLast = intervalWithLast,
            insertTime = System.currentTimeMillis()
        )
        handleShowDialog(wrapper)
    }

    /**
     * 在队列中移除DialogFragment
     */
    fun DialogQueueInterface?.dismissWithQueue() {
        this ?: return
        //当前展示的有它则直接dismiss
        _currentShowDialogs.find { it.dialogFragment == this }?.dismiss()
        //从队列中移除
        _dialogQueue.find { it.dialogFragment == this }?.also {
            _dialogQueue.remove(it)
        }
    }

    /**
     * 清空队列
     *
     * @param dismissCurrentDialog 是否dismiss掉正在展示的Dialog（默认为true）
     */
    fun clearQueue(dismissCurrentDialog: Boolean = true) {
        _dialogQueue.clear()
        _dismissListenerMap.clear()
        if (dismissCurrentDialog) {
            _currentShowDialogs.forEach {
                it.dismiss()
            }
        }
    }

    /*
     ******************************* 私有函数 ******************************************
     */

    /**
     * 处理展示Dialog
     */
    private fun handleShowDialog(wrapper: DialogWrapper) {
        //高优先级添加时，清空队列内所有其他元素
        if (wrapper.priority == PRIORITY_HIGH) {
            clearQueue()
        }
        //初始化
        wrapper.initQueueDialog()
        //默认优先级插到队尾，其他插到队首
        val insertPos = if (wrapper.priority == PRIORITY_DEFAULT) -1 else 0
        //加入队列
        insertToQueue(wrapper, insertPos)
        //显示Dialog
        showNextDialog(false)
    }

    /**
     * 展示下一个Dialog
     *
     *  @param isLastDismiss 是否为上一个Dialog dismiss触发的
     */
    private fun showNextDialog(isLastDismiss: Boolean) {
        //待展示的Dialog
        val nextDialog = _dialogQueue.getOrNull(0) ?: return
        //如果当前有显示的Dialog，默认优先级继续排队，其他优先级可以正常展示
        if (_currentShowDialogs.isNotEmpty() && nextDialog.priority == PRIORITY_DEFAULT) {
            return
        }
        //展示
        _dialogQueue.getOrNull(0)?.preShow(isLastDismiss) {
            //展示成功将其从队列中移除
            _currentShowDialogs.add(_dialogQueue.removeFirst())
        }
    }

    /**
     * 加入队列
     *
     * @param wrapper 需要展示的Dialog包装类
     * @param insertPos 插入位置，默认为-1，表示插入到队列末尾
     */
    private fun insertToQueue(wrapper: DialogWrapper, insertPos: Int = -1) {
        //如果队列中或展示中，存在高优先级，则不加入队列
        val queueHasHigh = _dialogQueue.find { it.priority == PRIORITY_HIGH }
        val showHasHigh = _currentShowDialogs.find { it.priority == PRIORITY_HIGH }
        if (queueHasHigh != null || showHasHigh != null) {
            "[insertToQueue] The Queue Or Showing has High Priority Data".logI()
            return
        }
        //插入
        if (insertPos >= 0) {
            _dialogQueue.add(insertPos, wrapper)
        } else {
            _dialogQueue.add(wrapper)
        }
        "[insertToQueue] ${wrapper.getMessage()}".logD()
    }

    /**
     * 初始化队列中的Dialog
     */
    private fun DialogWrapper.initQueueDialog() {
        dialog?.also { dialog ->
            //统一设置一下切换动画，防止切换时导致的闪烁问题
            dialog.window?.setWindowAnimations(R.style.dialog_queue_animation)
            //设置Dialog的OnDismissListener
            dialog.setOnDismissListener {
                "[Manager] [OnDismiss] ${this.getMessage()}".logW()
                //触发一下该Dialog原有的dismiss监听
                if (_dismissListenerMap[dialog] != null) {
                    _dismissListenerMap[dialog]?.onDismiss(dialog)
                    _dismissListenerMap.remove(dialog)
                }
                _currentShowDialogs.remove(this)
                showNextDialog(true)
            }
        }
        dialogFragment?.also { fragment ->
            fragment.triggerQueueDismiss {
                "[Manager] [OnDismiss] ${this.getMessage()}".logW()
                _currentShowDialogs.remove(this)
                showNextDialog(true)
            }
        }
    }

    /**
     * 预展示Dialog
     *
     * @param isLastDismiss 是否为上一个Dialog dismiss触发的
     * @param block 展示Dialog的回调
     */
    private fun DialogWrapper.preShow(isLastDismiss: Boolean, block: () -> Unit = {}) {
        //首次展示的延迟
        val currentTime = System.currentTimeMillis()
        val needShowTime = this.insertTime + this.firstShowDelay
        if (needShowTime > currentTime) {
            //先从队列中取出，延迟结束后再添加到队首
            _dialogQueue.remove(this@preShow)
            _scope.launch {
                delay(needShowTime - currentTime)
                "[preShow] [firstDelay] ${this@preShow.getMessage()}".logD()
                _dialogQueue.add(0, this@preShow)
                realShow(block)
            }
            //延迟时不要阻断队列中其他dialog的显示
            showNextDialog(false)
            return
        }
        //与上一个Dialog的间隔
        if (isLastDismiss && this.intervalWithLast > 0) {
            //延迟间隔的雨首次展示不同，要阻断队列
            _scope.launch {
                delay(this@preShow.intervalWithLast)
                "[preShow] [intervalLastDelay] ${this@preShow.getMessage()}".logD()
                realShow(block)
            }
            return
        }
        realShow(block)
    }

    /**
     * 真正展示Dialog
     */
    private fun DialogWrapper.realShow(block: () -> Unit) {
        if (this.isContextValid()) {
            if (_currentShowDialogs.isNotEmpty() && this.priority == PRIORITY_DEFAULT) {
                //当前有正在显示的Dialog，并且是默认优先级，则在列首接着排队
            } else {
                this.show()
                "[ShowDialog] ${this.getMessage()}".logI()
                block.invoke()
            }
        } else {
            "[DialogQueueManager] [ShowDialogError] [${
                this.getMessage()
            }] context is invalid".logW()
            //如果context不可用，则在队列中清除该dialog
            _dialogQueue.remove(this)
            dialog?.also {
                _dismissListenerMap.remove(it)
            }
        }
    }

    /**
     * Dialog实体包装类
     */
    private data class DialogWrapper(
        //dialog实体
        val dialog: Dialog? = null,
        //DialogFragment，这个比较特殊，每次都需要创建新的实例
        var dialogFragment: DialogQueueInterface? = null,
        private val fragmentActivity: WeakReference<AppCompatActivity>? = null,
        //优先级
        val priority: Int,
        //首次展示的延迟
        val firstShowDelay: Long = 0,
        //与上一个Dialog的间隔
        val intervalWithLast: Long = 0,
        //入列时间
        val insertTime: Long,
    ) {
        /**
         * 显示
         */
        fun show() {
            if (dialog != null) {
                dialog.show()
                return
            }
            if (dialogFragment != null) {
                fragmentActivity?.get()?.also {
                    dialogFragment?.queueShow(it)
                }
            }
        }

        /**
         * 隐藏
         */
        fun dismiss() {
            if (dialog != null) {
                dialog.dismiss()
                return
            }
            if (dialogFragment != null) {
                dialogFragment?.queueDismiss()
                return
            }
        }

        /**
         * 判断Dialog的context是否可用
         */
        fun isContextValid(): Boolean {
            if (dialog != null) {
                var currentContext = dialog.context
                // 如果上下文是 Activity，直接判断它的生命周期
                if (currentContext is Activity) {
                    return !currentContext.isFinishing && !currentContext.isDestroyed
                }
                // 如果上下文是 ContextWrapper（例如 ContextThemeWrapper），递归查找实际的 Activity 上下文
                while (currentContext is ContextWrapper) {
                    currentContext = currentContext.baseContext
                    if (currentContext is Activity) {
                        // 找到 Activity 后，检查生命周期
                        return !currentContext.isFinishing && !currentContext.isDestroyed
                    }
                }
                // 如果没有找到有效的 Activity 上下文，返回 false
                return false
            }
            if (dialogFragment != null) {
                return fragmentActivity?.get() != null && fragmentActivity.get()?.isFinishing == false && fragmentActivity.get()?.isDestroyed == false
            }
            return false
        }

        /**
         * TODO：测试方法，回头删除
         */
        fun getMessage(): String {
            if (dialog != null) {
                return if (dialog is TestDialog) {
                    dialog.getContent()
                } else {
                    "The Dialog is not TestDialog"
                }
            }
            if (dialogFragment != null) {
                return "This is DialogFragment"
            }
            return "Error"
        }
    }

    /**
     * DialogFragment要实现这个接口
     */
    interface DialogQueueInterface {

        //显示
        fun queueShow(activity: AppCompatActivity)

        //隐藏
        fun queueDismiss()

        //触发onDismiss
        fun triggerQueueDismiss(block: (() -> Unit)?)
    }
}